﻿using Furion.CMS.Core;
using Furion.CMS.Domain;
using Furion.FriendlyException;
using Furion.Logging.Extensions;
using Furion.RemoteRequest;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Application.RemoteProxy
{
    /// <summary>
    /// 阿里云短信代理
    /// </summary>
    [Timeout(10000)]
    public interface IAliyunSMSProxy : IHttpDispatchProxy
    {
        /// <summary>
        /// 通用短信发送
        /// </summary>
        /// <param name="phoneNumber"></param>
        /// <param name="signName"></param>
        /// <param name="templateCode"></param>
        /// <param name="templateParam"></param>
        /// <returns></returns>
        [Get("https://dysmsapi.aliyuncs.com/?Action=SendSms&Version=2017-05-25&PhoneNumbers={phoneNumber}&SignName={signName}&TemplateCode={templateCode}&TemplateParam={templateParam}")]
        Task<HttpResponseMessage> SendAsync(string phoneNumber, string signName, string templateCode, string templateParam = "{}");

        #region Interceptor Handler
        /// <summary>
        /// 客户端拦截
        /// </summary>
        [Interceptor(InterceptorTypes.Client)]
        static void OnClientCreating(HttpClient req)
        {

        }

        /// <summary>
        /// 请求拦截
        /// </summary>
        /// <param name="req"></param>
        [Interceptor(InterceptorTypes.Request)]
        static void OnRequesting(HttpRequestMessage req)
        {
            var repository = App.GetRequiredService<DatabaseAccessor.IRepository<SiteSetting>>();
            var settings = repository.FirstOrDefault(false);

            var uriQueryString = req.RequestUri.Query;
            var httpMethod = req.Method.Method.ToUpper();
            var stringToSign = $"{httpMethod}&%2F&{System.Web.HttpUtility.UrlEncode(uriQueryString)}";
            

            if (settings.SmsServerProvider == Core.SmsServerProviders.Unknown)
                throw Oops.Oh("短信服务调用失败,请与管理员联系");

            // 追加签名相关参数
            req.AppendQueries(new Dictionary<string, object> {
                { "AccessKeyId", settings.SmsAccessParam.KeyId},
                // 签名唯一随机数。用于防止网络重放攻击
                { "SignatureNonce", Guid.NewGuid().ToString("N")},
                // 请求的时间戳。按照ISO8601标准表示，并需要使用UTC时间，格式为yyyy-MM-ddTHH:mm:ssZ.
                { "Timestamp", DateTime.Now.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",CultureInfo.CurrentCulture)},
                { "SignatureMethod", "1.0"},
                { "Signature", stringToSign.ToBase64HMAC(settings.SmsAccessParam.KeySecret)}
            });
        }

        /// <summary>
        /// 错误拦截处理
        /// </summary>
        /// <param name="req"></param>
        /// <param name="errors"></param>
        [Interceptor(InterceptorTypes.Exception)]
        static void OnException(HttpResponseMessage req, string errors)
        {
            switch (req?.StatusCode)
            {
                case System.Net.HttpStatusCode.Unauthorized:
                case System.Net.HttpStatusCode.Forbidden:
                    $"阿里云短信授权签名验证未通过或无权访问，请求地址：{req.RequestMessage?.RequestUri}".LogError<IAliyunSMSProxy>();
                    break;
                case System.Net.HttpStatusCode.BadRequest:
                case System.Net.HttpStatusCode.InternalServerError:
                    $"请求的服务发生内部错误[ErrorCode:{System.Net.HttpStatusCode.BadRequest}]，请求地址：{req.RequestMessage?.RequestUri}".LogError<IAliyunSMSProxy>();
                    break;
                default:
                    $"请求的服务发生错误{errors}，请求地址：{req?.RequestMessage?.RequestUri}".LogError<IAliyunSMSProxy>();
                    break;
            }
        }
        #endregion
    }
}
